å ¥åãœãŒã¹ã®åé¡ãšã³ã³ãããŒã©ãŒã¿ã€ãã®æ€åºããã¹ã¿ãŒããã·ãŒã ã¬ã¹ãªWebXRäœéšãå®çŸããŸãããããã®å æ¬çãªã¬ã€ãã¯ãã°ããŒãã«ãªèŠèŽè åãã«ãã®è©³çŽ°ãæ¢ããŸãã
æ²¡å ¥åäœéšã®ããã²ãŒãïŒWebXRå ¥åãœãŒã¹ã®åé¡ãšã³ã³ãããŒã©ãŒã¿ã€ãã®æ€åº
ä»®æ³çŸå®ïŒVRïŒãšæ¡åŒµçŸå®ïŒARïŒãå«ãæ¡åŒµçŸå®ïŒXRïŒã®é åã¯ãæ¥éã«é²åããŠããŸããéçºè ãããçŽæçã§é åçãªæ²¡å ¥åäœéšãåµé ããããšåªåããäžã§ããŠãŒã¶ãŒå ¥åã®çè§£ãšå¹æçãªç®¡çãæãéèŠã«ãªããŸããWebXRã¯ããŠã§ããã©ãŠã¶ãéããŠçŽæ¥XRã³ã³ãã³ããé ä¿¡ããããã®æšæºã§ããããã®ããã®åŒ·åãªããŒã«ãæäŸããŠããŸããå ç¢ãªWebXRã¢ããªã±ãŒã·ã§ã³ãæ§ç¯ããäžã§éèŠãªåŽé¢ã¯ãå ¥åãœãŒã¹ãåé¡ããã³ã³ãããŒã©ãŒã¿ã€ããæ€åºããèœåã§ããããã«ããã倿§ãªããŒããŠã§ã¢éã§ãã«ã¹ã¿ãã€ãºãããã€ã³ã¿ã©ã¯ã·ã§ã³ãã¢ã¯ã»ã·ããªãã£ã®åäžããããŠããäžè²«ãããŠãŒã¶ãŒãšã¯ã¹ããªãšã³ã¹ãå¯èœã«ãªããŸãã
å ¥åãœãŒã¹åé¡ã®éèŠæ§
æ²¡å ¥åç°å¢ã§ã¯ããŠãŒã¶ãŒã®ã€ã³ã¿ã©ã¯ã·ã§ã³ã¯æ§ã ãªå ¥åããã€ã¹ãä»ããŠè¡ãããŸãããããã¯ãåçŽãªèŠç·ããŒã¹ã®éžæãããæŽç·Žããã远跡ã³ã³ãããŒã©ãŒããã³ããžã§ã¹ãã£ãŒãããã«ã¯èº«äœã®åããŸã§å€å²ã«ããããŸããWebXRã¢ããªã±ãŒã·ã§ã³ãé©åãã€èªç¶ã«å¿çããããã«ã¯ãã©ã®ãããªçš®é¡ã®å ¥åãæäŸãããŠããããçè§£ããå¿ èŠããããŸããããã§å ¥åãœãŒã¹ã®åé¡ãéèŠãªåœ¹å²ãæãããŸãã
ãã®åé¡ãã°ããŒãã«ãªèŠèŽè ã«ãšã£ãŠãªãããã»ã©éèŠãªã®ã§ããããïŒ
- ããŒããŠã§ã¢ã®å€æ§æ§ïŒ XRåžå Žã«ã¯ãããŸããŸãªäŸ¡æ Œåž¯ããã©ãŒã ãã¡ã¯ã¿ãæã€å€æ°ã®ã¡ãŒã«ãŒããã®ããã€ã¹ã溢ããŠããŸããã°ããŒãã«ãªã¢ããªã±ãŒã·ã§ã³ã¯ããã®ç°è³ªæ§ãé©åã«åŠçããå¿ èŠããããŸããäŸãã°ãValve Indexã®ãããªãã€ãšã³ãPC VRãããã»ããåãã«èšèšãããVRäœéšã¯ãMeta Questã®ãããªã¹ã¿ã³ãã¢ãã³ã®ã¢ãã€ã«VRãããã»ããããMagic LeapãARKit/ARCoreãå®è¡ããã¹ããŒããã©ã³ã®ãããªARããã€ã¹ã察象ãšãããã®ãšã¯ãå ¥åèœåãç°ãªããŸãã
- ãŠãŒã¶ãŒã®æåŸ ïŒ ãŠãŒã¶ãŒã¯ãèªåãéžãã XRããã€ã¹ãã¢ããªã±ãŒã·ã§ã³å ã§äºæž¬éãã«åäœããããšãæåŸ ããŸããå ¥åã®èª€è§£éã«ãã£ãŠã³ã³ãããŒã©ãŒã®ãã¿ã³ãæŒããŠãæåŸ ããã¢ã¯ã·ã§ã³ãå®è¡ãããªãå Žåãããã¯ãã©ã¹ãã¬ãŒã·ã§ã³ã«ã€ãªããããŠãŒã¶ãŒãäœéšããããã«é¢è±ãããŠããŸãå¯èœæ§ããããŸãã
- ã¢ã¯ã»ã·ããªãã£ïŒ ç°ãªãå ¥åæ¹æ³ã¯ãããŸããŸãªãŠãŒã¶ãŒã®ããŒãºãèœåã«å¯Ÿå¿ããŸããå ¥åãåé¡ããããšã§ãéçºè ã¯ä»£æ¿ã®ã€ã³ã¿ã©ã¯ã·ã§ã³æ¹æ³ãæäŸã§ããããå€ãã®äººã ãæ²¡å ¥åã³ã³ãã³ãã«ã¢ã¯ã»ã¹ããæ¥œããããšãã§ããããã«ãªããŸããäŸãã°ãæã®åããå¶éãããŠãããŠãŒã¶ãŒã¯ãèŠç·ãé³å£°å ¥åã«é Œãããšãå€ããããããŸããã
- ããã©ãŒãã³ã¹ã®æé©åïŒ å ¥åãœãŒã¹ã®èœåãç¥ãããšã¯ãæé©åæŠç¥ãç«ãŠãäžã§æçã§ããäŸãã°ãè€éãªãã³ããã©ããã³ã°ã¯ãåçŽãªã²ãŒã ããããããå€ãã®åŠçèœåãå¿ èŠãšããå ŽåããããŸãã
- ãã©ãããã©ãŒã ã®äžè²«æ§ïŒ WebXRã¯çµ±äžãããAPIãç®æããŠããŸãããåºç€ãšãªãããŒããŠã§ã¢ã®å®è£ ã¯ç°ãªãããšããããŸããå ç¢ãªåé¡ã¯ããããã®ã®ã£ãããåããããçšåºŠã®äžè²«æ§ãç¶æããã®ã«åœ¹ç«ã¡ãŸãã
WebXRå ¥åãœãŒã¹ã®çè§£
WebXR Device APIã¯ãæ¥ç¶ãããå
¥åããã€ã¹ã«é¢ããæ
å ±ã«ã¢ã¯ã»ã¹ããã¡ã«ããºã ãæäŸããŸããããããšå¯Ÿè©±ããäž»ãªæ¹æ³ã¯XRInputSourceãªããžã§ã¯ããéããŠã§ãããããã¯XRã»ãã·ã§ã³ã«æ¥ç¶ãããåäžã®å
¥åãœãŒã¹ã衚ããŸããXRInputSourceãªããžã§ã¯ãã¯ä»¥äžã®æ
å ±ãæäŸããŸãïŒ
- Target RayïŒã¿ãŒã²ããã¬ã€ïŒïŒ å ¥åãœãŒã¹ãæããŠããæ¹åã
- GripïŒã°ãªããïŒïŒ 空éå ã§ã®å ¥åãœãŒã¹ã®ããŒãºã§ããã°ãã°ä»®æ³çãªæãã³ã³ãããŒã©ãŒãä¿æããå Žæã衚ããŸãã
- ProfilesïŒãããã¡ã€ã«ïŒïŒ å ¥åãœãŒã¹ã®èœåãšæåŸ ãããåäœãèšè¿°ããæååãŸãã¯æååã®é åã
- HandednessïŒå©ãæïŒïŒ å ¥åãœãŒã¹ãå·Šæçšã峿çšãã
- FeaturesïŒæ©èœïŒïŒ ãã¿ã³ããµã ã¹ãã£ãã¯ãã¿ããããããªã©ãå©çšå¯èœãªç¹å®ã®å ¥åæ©èœã
`XRInputSource.profiles`ããããã£ïŒåé¡ã®éµ
profilesããããã£ã¯ãå
¥åãœãŒã¹ãåé¡ããããã®æã匷åãªããŒã«ãšèšããã§ããããããã¯ããã³ããŒãå
¥åããã€ã¹ã®çš®é¡ãšèœåã瀺ãããã«äœ¿çšããæååã®é
åã§ãããããã®ãããã¡ã€ã«ã¯ãKhronos Groupã®Extensible XR Input Profile仿§ã«ãã£ãŠæšæºåãããŠãããXRå
¥åããã€ã¹ãèšè¿°ããããã®å
±éèšèªãæäŸããããšãç®æããŠããŸãã
äžè¬çãªãããã¡ã€ã«ã®äŸïŒ
'generic-hand'ïŒæ±çšã®ãã³ããã©ããã³ã°å ¥åãœãŒã¹ã瀺ããŸãã'google-daydream-controller'ïŒç¹ã«Google Daydreamã³ã³ãããŒã©ãŒçšã'htc-vive-controller'ïŒHTC Viveã³ã³ãããŒã©ãŒçšã'oculus-touch-controller'ïŒOculusïŒçŸMetaïŒTouchã³ã³ãããŒã©ãŒçšã'microsoft-mixed-reality-controller'ïŒWindows Mixed Realityã³ã³ãããŒã©ãŒçšã'microsoft-edge-motion-controller'ïŒMicrosoft Edgeã«é¢é£ä»ããããã¢ãŒã·ã§ã³ã³ã³ãããŒã©ãŒçšã'vive-tracker'ïŒHTC Vive Trackerçšã'keyboard'ïŒããŒããŒãå ¥åã衚ããŸãã'mouse'ïŒããŠã¹å ¥åã衚ããŸãã
ãããã®ãããã¡ã€ã«æååã確èªããããšã§ãéçºè ã¯ã³ã³ãããŒã©ãŒã®ã¿ã€ãã倿ããã¢ããªã±ãŒã·ã§ã³ã®ããžãã¯ãããã«åãããŠèª¿æŽããããšãã§ããŸãã
ã³ã³ãããŒã©ãŒã¿ã€ãã®æ€åºïŒå®è·µçãªã¢ãããŒã
ã³ã³ãããŒã©ãŒã¿ã€ãæ€åºã®æ žå¿ã¯ãã¢ã¯ãã£ããªXRã»ãã·ã§ã³å
ã§æ¥ç¶ãããXRInputSourceãªããžã§ã¯ããå埩åŠçãããããã®profilesããããã£ã調ã¹ãããšã«ãããŸãã
ã¹ããããã€ã¹ãããã®æ€åºããžãã¯
- XRã»ãã·ã§ã³ã®ååŸïŒ ãŸããã¢ã¯ãã£ããª
XRSessionãå¿ èŠã§ããããã¯éåžžããŠãŒã¶ãŒãXRã»ãã·ã§ã³ããªã¯ãšã¹ããããããæ£åžžã«éå§ãããåŸã«ååŸãããŸããnavigator.xr.requestSession('immersive-vr').then(session => { // Session started, now we can access input sources session.addEventListener('inputsourceschange', handleInputSourcesChange); handleInputSourcesChange({ session }); // Initial check }); - å
¥åãœãŒã¹ãžã®ã¢ã¯ã»ã¹ïŒ `session.inputSources`ããããã£ã¯ãæ¥ç¶ãããŠãããã¹ãŠã®
XRInputSourceãªããžã§ã¯ãã®é åãæäŸããŸããfunction handleInputSourcesChange(event) { const session = event.session; const inputSources = session.inputSources; inputSources.forEach(inputSource => { // Classify each inputSource here classifyInputSource(inputSource); }); } - å埩ãšåé¡ïŒ åé¡é¢æ°å
ã§ãå
XRInputSourceã®profilesé åãã«ãŒãåŠçããŸããfunction classifyInputSource(inputSource) { console.log('Input Source Profiles:', inputSource.profiles); if (inputSource.profiles.includes('oculus-touch-controller')) { console.log('Detected Oculus Touch Controller!'); // Apply Oculus Touch specific logic handleOculusTouch(inputSource); } else if (inputSource.profiles.includes('htc-vive-controller')) { console.log('Detected HTC Vive Controller!'); // Apply HTC Vive specific logic handleViveController(inputSource); } else if (inputSource.profiles.includes('generic-hand')) { console.log('Detected Hand Tracking!'); // Apply hand tracking specific logic handleHandTracking(inputSource); } else if (inputSource.profiles.includes('mouse') || inputSource.profiles.includes('keyboard')) { console.log('Detected 2D Input (Mouse/Keyboard)'); // Apply 2D input logic handle2DInput(inputSource); } // Add more else if conditions for other profiles } - å
¥åã€ãã³ãã®åŠçïŒ ã³ã³ãããŒã©ãŒã®ã¿ã€ããç¹å®ããããç¹å®ã®å
¥åã€ãã³ãïŒäŸïŒãã¿ã³æŒäžããµã ã¹ãã£ãã¯ã®åãïŒããªãã¹ã³ããããããã¢ããªã±ãŒã·ã§ã³ã®ã¢ã¯ã·ã§ã³ã«ãããã³ã°ã§ããŸãã
XRSessionã®`input`ã€ãã³ããè¯ãåºçºç¹ã§ãããç¹å®ã®ã³ã³ãããŒã©ãŒã«ã¯ç¬èªã®ã€ãã³ããªã¹ããŒãããããããŒãªã³ã°ãå¿ èŠãªå ŽåããããŸããsession.addEventListener('selectstart', (event) => { if (event.inputSource.profiles.includes('oculus-touch-controller')) { console.log('Oculus Touch Trigger Pressed!'); // Trigger specific action for Oculus Touch } });
ãããã¡ã€ã«ãèŠã€ãããªãããŸãã¯æ±çšã®å Žåã®å¯ŸåŠæ³
ãã¹ãŠã®XRããã€ã¹ãéåžžã«å
·äœçãªãããã¡ã€ã«ãå
¬éããŠãããšã¯éããŸããããã®ãããªå Žåã'generic-xr-controller'ã®ãããªããæ±çšçãªãããã¡ã€ã«ã«ééãããããããã¡ã€ã«ããŸã£ãããªãå ŽåããããŸãããã®ãããªç¶æ³ã§ã¯ããã©ãŒã«ããã¯æŠç¥ãäžå¯æ¬ ã§ãïŒ
- Gamepad APIãžã®ãã©ãŒã«ããã¯ïŒ
XRInputSourceãgamepadããããã£ãå ¬éããŠããå Žåãæšæºã®Gamepad APIã«ãã©ãŒã«ããã¯ã§ããŸããããã«ãããã³ã³ãããŒã©ãŒã®æ£ç¢ºãªã¢ãã«ããããã¡ã€ã«ã«ãã£ãŠæç€ºçã«èå¥ãããªããŠãããã¿ã³ã®æŒäžã軞ã®å€ã«ã¢ã¯ã»ã¹ããããã®ããæ®éçãªæ¹æ³ãæäŸãããŸããWebXR APIã¯ãå®è³ªçã«XRã³ã³ããã¹ãã®ããã«Gamepad APIãæ©æž¡ãããŸãã - ããã©ã«ãã®ã€ã³ã¿ã©ã¯ã·ã§ã³ïŒ å šãèªèãããªãå ¥åãœãŒã¹ããå°çšã³ã³ãããŒã©ãŒããªãããã€ã¹ïŒåçŽãªVRãã¥ãŒã¢ãªã©ïŒã®å Žåãããã©ã«ãã®ã€ã³ã¿ã©ã¯ã·ã§ã³ãå®è£ ããå¿ èŠããããããããŸãããããã«ã¯ãèŠç·ããŒã¹ã®éžæããããã»ããã®ç°¡åãªãã¿ã³ããŸãã¯äºææ§ã®ããã²ãŒã ãããããŠãŒã¶ãŒã«æ¥ç¶ããããèŠæ±ããããšãå«ãŸããå ŽåããããŸãã
- ãŠãŒã¶ãŒãžã®ããã³ããïŒ ææ§ãªç¶æ³ã§ã¯ããŠãŒã¶ãŒã«ããã³ããã衚瀺ããã®ãæåçã§ããããšãå€ãã§ããäŸãã°ãæ±çšã³ã³ãããŒã©ãŒãæ€åºãããå Žåããããã¯ã¢ãŒã·ã§ã³ã³ã³ãããŒã©ãŒã§ããããããšãã²ãŒã ãããã§ããïŒããšå°ããããšãã§ããŸããããã«ããããŠãŒã¶ãŒã¯ã¢ããªã±ãŒã·ã§ã³ã®å ¥åãããã³ã°ãã¬ã€ãããããšãã§ããŸãã
é«åºŠãªåé¡ãšèæ ®äºé
ãããã¡ã€ã«æååãäž»èŠãªã¡ã«ããºã ã§ããäžæ¹ãå æ¬çãªWebXRå ¥åæŠç¥ã®ããã«ã¯èæ ®ãã¹ãä»ã®èŠå ããããŸãïŒ
1. ãã³ããã©ããã³ã° vs. ã³ã³ãããŒã©ãŒãã©ããã³ã°
ãã³ããã©ããã³ã°ïŒäŸïŒ'generic-hand'ïŒãšç©ççãªã³ã³ãããŒã©ãŒãã©ããã³ã°ãåºå¥ããããšã¯éåžžã«éèŠã§ãããã³ããã©ããã³ã°ã¯ããèªç¶ã§ã³ã³ãããŒã©ãŒäžèŠã®ã€ã³ã¿ã©ã¯ã·ã§ã³ãæäŸããŸããããã®ç²ŸåºŠãšè¿œè·¡ã®å¿ å®åºŠã¯å€åããå¯èœæ§ããããŸããã³ã³ãããŒã©ãŒãã©ããã³ã°ã¯ãèªç¶ãã¯å£ããŸããã现ããéåå¶åŸ¡ãå¿
èŠãšããã¢ã¯ã·ã§ã³ã«å¯ŸããŠãããæ£ç¢ºã§äžè²«ããå
¥åãæäŸããããšãå€ãã§ãã
äŸïŒ ãŠãŒã¶ãŒãæç»ã§ããVRã¢ããªã±ãŒã·ã§ã³ã§ã¯ãèªç±åœ¢åŒã®æç»ãžã§ã¹ãã£ãŒã«ã¯ãã³ããã©ããã³ã°ã䜿çšãããã§ããããããããæ£ç¢ºãªãªããžã§ã¯ãæäœããã¿ã³ã®èµ·åã«ã¯ãã³ã³ãããŒã©ãŒã®æ¹ã奜ãŸãããããããŸãããåé¡ããžãã¯ã¯ããããã®ã¢ãŒããåãæ¿ããããæèã«å¿ããŠäœ¿çšãããã§ããããã«ããå¿ èŠããããŸãã
2. å ¥åãœãŒã¹ã®æ©èœ
åãªãã¿ã€ãã ãã§ãªããXRInputSourceã§å©çšå¯èœãªæ©èœã調ã¹ãããšã§ãåé¡ãšã€ã³ã¿ã©ã¯ã·ã§ã³ãã¶ã€ã³ãæŽç·Žãããããšãã§ããŸãã`profiles`ã¯é«ã¬ãã«ã®ãã³ããäžããŸãããç¹å®ã®èœåã確èªããæ¹ãããå
ç¢ã§ãã
- ãã¿ã³ïŒ ããªã¬ãŒãã¿ã³ãã°ãªãããã¿ã³ãã¡ãã¥ãŒãã¿ã³ã¯ãããŸããïŒ
- è»žïŒ ã¢ããã°å ¥åãæäŸãããµã ã¹ãã£ãã¯ãã¿ãããããã¯ãããŸããïŒ
- ã»ã³ãµãŒïŒ è§ŠèŠãã£ãŒãããã¯æ©èœã¯ãããŸããïŒ
WebXR Input Profiles仿§ã¯ããããã®æ©èœïŒäŸïŒ'trigger', 'squeeze', 'thumbstick', 'touchpad', 'button'ïŒã®ããã®å
±éã®èªåœãå®çŸ©ããŠããŸãããããã®æ©èœã®ååšã確èªã§ããŸãã
泚ïŒAPIãæ®éçã«äŸ¿å©ãªæ¹æ³ã§çŽæ¥å ¬éããŠããªãå Žåãæ©èœã®çŽæ¥çãªç¢ºèªã¯ãåºç€ãšãªãXRã©ã³ã¿ã€ã ãšã®ããçŽæ¥çãªå¯Ÿè©±ãããªãã£ã«ãå¿ èŠã«ãªãå ŽåããããŸãããããã`profiles`ã¯å©çšå¯èœãªæ©èœãšåŒ·ãçžé¢ããŠããããšãå€ãã§ãã
3. å©ãæ
inputSource.handednessããããã£ïŒ'left'ãŸãã¯'right'ïŒã¯ãä»®æ³ã®æãæ£ããæ¹åä»ããããå·Šæçšã®ã³ã³ãããŒã«ãå²ãåœãŠããããããã«äžå¯æ¬ ã§ããããã¯åçŽã§ãããå¿«é©ãªäœéšã®ããã«ã¯å¿
é ã§ãã
4. ã¿ãŒã²ããã¬ã€ã¢ãŒã
inputSource.targetRayModeããããã£ã¯'gaze'ãŸãã¯'pointing'ã®ããããã«ãªããŸããããã¯ãå
¥åãã©ã®ããã«åããããŠãããã瀺ããŸãïŒ
'gaze'ïŒ å ¥åã¯ãŠãŒã¶ãŒãèŠãŠããæ¹åã«ãã£ãŠåããããŸããããã¯ãããã»ããã®ã¿ã®VRäœéšããç¹å®ã®ARã€ã³ã¿ã©ã¯ã·ã§ã³ã§äžè¬çã§ãã'pointing'ïŒ å ¥åã¯ç©ççãªã³ã³ãããŒã©ãŒãŸãã¯è¿œè·¡ãããæã«ãã£ãŠåããããŸããããã¯ã³ã³ãããŒã©ãŒã§ããäžè¬çãªã¢ãŒãã§ãã
ãããçè§£ããããšã¯ãé©åãªã€ã³ã¿ã©ã¯ã·ã§ã³ã®ã¡ã¿ãã¡ãŒã決å®ããã®ã«åœ¹ç«ã¡ãŸãã'gaze'ã®å ŽåããŠãŒã¶ãŒã®èŠç·ã«è¿œåŸããã«ãŒãœã«ã䜿çšããããšããããŸãã'pointing'ã®å Žåãã¬ã€ã¯ã³ã³ãããŒã©ãŒãŸãã¯æããçºä¿¡ãããŸãã
5. å ¥åãããã³ã°ã®ã°ããŒãã«å
profilesã¯åºçºç¹ãæäŸããŸãããçã®ã°ããŒãã«ãªã¢ããªã±ãŒã·ã§ã³èšèšã«ã¯ããããã®æšæºåããããããã¡ã€ã«ããŠãŒã¶ãŒäžå¿ã®ã€ã³ã¿ã©ã¯ã·ã§ã³ã«ãããã³ã°ããå¿
èŠããããŸãã以äžãèæ
®ããŠãã ããïŒ
- ãã¿ã³ãããã³ã°ã®æ £ç¿ïŒ ãããã¡ã€ã«ã¯ãã¿ã³ã®ã¿ã€ãïŒäŸïŒãããªã¬ãŒãïŒã瀺åããŸãããæ£ç¢ºãªã¢ã¯ã·ã§ã³ïŒäŸïŒçºå°ãéžæãæŽãïŒã¯èšå®å¯èœã§ããããå°åãã¢ããªã±ãŒã·ã§ã³ã®ãžã£ã³ã«ããšã®äžè¬çãªæ £ç¿ã«åŸãå¿ èŠããããããããŸãããäŸãã°ãå€ãã®è¥¿æŽã®ã²ãŒã ã§ã¯ãäž»èŠãªã¢ã¯ã·ã§ã³ãã¿ã³ã¯å³ã®ã³ã³ãããŒã©ãŒã«ãããããããŸããããããã¯æ®éçãªçå®ã§ã¯ãããŸããã
- èšèªãšã¢ã€ã³ã³ïŒ ã³ã³ãããŒã«ã«é¢é£ããUIèŠçŽ ãããŒã«ã©ã€ãºãããŠããããšã確èªããŠãã ãããã¢ã€ã³ã³ã¯äžè¬çã«æ®éçã§ãããããã¹ãã©ãã«ã¯ç¿»èš³ããå¿ èŠããããŸãã
- å ¥åã¢ã¯ã»ã·ããªãã£ãããã¡ã€ã«ïŒ ç¹æ®ãªé©å¿åã³ã³ãããŒã©ãŒãªã©ãã¢ã¯ã»ã·ããªãã£ãœãªã¥ãŒã·ã§ã³ã®äžéšã§ããå¯èœæ§ã®ããå ¥åãœãŒã¹ãèå¥ããããã«ãåé¡ãæ¡åŒµããããšãæ€èšããŠãã ãããWebXRã®çŸåšã®ãããã¡ã€ã«ã·ã¹ãã ã¯ããã¹ãŠã®ããããªã¢ã¯ã»ã·ããªãã£ããã€ã¹ã«æç€ºçã«å¯Ÿå¿ããŠããããã§ã¯ãããŸããããæ¡åŒµå¯èœãªæè»ãªã·ã¹ãã ã¯æçã§ãã
äŸïŒãã«ãã³ã³ãããŒã©ãŒã¢ããªã±ãŒã·ã§ã³ã®æ§ç¯
Oculus Touchã³ã³ãããŒã©ãŒãšãã³ããã©ããã³ã°ã®äž¡æ¹ã§åäœããããã«èšèšãããæ€åºãããå ¥åãœãŒã¹ã«åºã¥ããŠç°ãªãUIèŠçŽ ãã³ã³ãããŒã«ã衚瀺ããWebXRã¢ããªã±ãŒã·ã§ã³ã®ç°¡ç¥åãããäŸãèããŠã¿ãŸãããã
ã·ããªãªïŒ ãŠãŒã¶ãŒã3Dãªããžã§ã¯ããšå¯Ÿè©±ã§ããVRã¢ããªã±ãŒã·ã§ã³ãOculus Touchã³ã³ãããŒã©ãŒã䜿çšããå ŽåããŠãŒã¶ãŒã¯ã°ãªãããã¿ã³ã§ãªããžã§ã¯ããæŽã¿ãããªã¬ãŒã§æã瀺ãããšãã§ããŸãããã³ããã©ããã³ã°ã䜿çšããå ŽåããŠãŒã¶ãŒã¯ãã³ããžã§ã¹ãã£ãŒã§æŽã¿ãæã瀺ãããšã§UIèŠçŽ ãšå¯Ÿè©±ã§ããŸãã
let session = null;
let controllers = {}; // To store input sources by their ID
function setupXR() {
navigator.xr.requestSession('immersive-vr').then(xrSession => {
session = xrSession;
session.addEventListener('inputsourceschange', handleInputSourcesChange);
session.addEventListener('selectstart', handleSelectStart);
session.addEventListener('squeezestart', handleSqueezeStart);
session.addEventListener('end', () => {
session = null;
console.log('XR session ended.');
});
handleInputSourcesChange({ session: session }); // Initial sync
console.log('XR session started.');
}).catch(err => {
console.error('Error requesting XR session:', err);
});
}
function handleInputSourcesChange(event) {
const inputSources = event.session.inputSources;
// Clear out old controllers that are no longer connected
for (const id in controllers) {
if (!inputSources.find(src => src.handedness === controllers[id].handedness)) {
delete controllers[id];
// Potentially update UI to reflect disconnected controller
console.log(`Controller ${id} disconnected.`);
}
}
// Process new and existing input sources
inputSources.forEach(inputSource => {
controllers[inputSource.gamepad.index] = inputSource; // Using gamepad index as a stable ID
classifyInputSource(inputSource);
});
}
function classifyInputSource(inputSource) {
console.log('Input Source ID:', inputSource.gamepad.index, 'Profiles:', inputSource.profiles);
if (inputSource.profiles.includes('oculus-touch-controller')) {
console.log(`Oculus Touch Controller (${inputSource.handedness}) detected.`);
// Assign specific handlers or states for Oculus Touch
if (inputSource.handedness === 'left') {
controllers[inputSource.gamepad.index].type = 'oculus_touch_left';
} else {
controllers[inputSource.gamepad.index].type = 'oculus_touch_right';
}
} else if (inputSource.profiles.includes('generic-hand')) {
console.log(`Hand Tracking (${inputSource.handedness}) detected.`);
controllers[inputSource.gamepad.index].type = 'hand_tracking';
// Potentially update UI to show hand tracking indicators
} else {
console.log(`Unknown controller type or generic gamepad (${inputSource.handedness}) detected.`);
controllers[inputSource.gamepad.index].type = 'generic';
}
}
function handleSelectStart(event) {
const inputSource = controllers[event.inputSource.gamepad.index];
if (!inputSource) return;
console.log('Select Start on:', inputSource.type);
switch(inputSource.type) {
case 'oculus_touch_right': // Assuming primary select is trigger for right controller
console.log('Oculus Touch Trigger pressed. Grabbing object or activating UI.');
// Implement grab/activate logic for Oculus Touch
break;
case 'hand_tracking':
console.log('Hand Pinch detected. Interacting with UI.');
// Implement UI interaction logic for hand tracking pinch
break;
case 'generic':
console.log('Generic controller select pressed.');
// Fallback for generic controllers
break;
}
}
function handleSqueezeStart(event) {
const inputSource = controllers[event.inputSource.gamepad.index];
if (!inputSource) return;
console.log('Squeeze Start on:', inputSource.type);
switch(inputSource.type) {
case 'oculus_touch_left': // Assuming grip is squeeze for left controller
console.log('Oculus Touch Grip pressed. Grabbing object.');
// Implement grab logic for Oculus Touch grip
break;
case 'hand_tracking':
console.log('Hand Grip (closed fist) detected. Grabbing object.');
// Implement grab logic for hand tracking closed fist
break;
case 'generic':
console.log('Generic controller squeeze pressed.');
// Fallback for generic controllers
break;
}
}
// Call setupXR() when your application is ready to start an XR session.
// For example, on a button click:
// document.getElementById('enter-vr-button').addEventListener('click', setupXR);
// You would also need to handle input release events (selectend, squeezeend)
// and potentially other input events like thumbstick/touchpad movement.
課é¡ãšä»åŸã®æ¹åæ§
鲿©ã«ããããããã課é¡ã¯æ®ã£ãŠããŸãïŒ
- ãããã¡ã€ã«ã®æšæºåïŒ æ¹åãããŠã¯ãããã®ã®ãæšæºåããããããã¡ã€ã«ã®ãªã¹ãã¯ãŸã æé·äžã§ããããã³ããŒã¯ã«ã¹ã¿ã ãŸãã¯èšè¿°ã®å°ãªããããã¡ã€ã«ãå®è£ ããå¯èœæ§ããããŸãã
- ããã€ã¹ã®ãšãã¥ã¬ãŒã·ã§ã³ïŒ å¹ åºãããã€ã¹ã§ãã¹ãããããšã¯å°é£ã§ãããšãã¥ã¬ãŒã¿ãŒã¯åœ¹ç«ã¡ãŸãããå®éã®ããŒããŠã§ã¢ã®ããã©ãŒãã³ã¹ãã€ã³ã¿ã©ã¯ã·ã§ã³ã®ãã¥ã¢ã³ã¹ãå®å šã«åçŸããããã§ã¯ãããŸããã
- ãŠãŒã¶ãŒã®æå³ã®äºæž¬ïŒ æ£ç¢ºãªåé¡ãã§ããŠããç¹ã«å©çšå¯èœãªå ¥åæ¹æ³ã倿§ã§ããå ŽåããŠãŒã¶ãŒã®æ£ç¢ºãªæå³ãæšæž¬ããããšã¯è€éã«ãªãå¯èœæ§ããããŸãã
- ã¯ãã¹ãã©ãããã©ãŒã ã®ãã¥ã¢ã³ã¹ïŒ WebXRã¯ã¯ãã¹ãã©ãããã©ãŒã ã®äºææ§ãç®æããŠããŸãããã¬ã³ããªã³ã°ãã€ãã©ã€ã³ã远跡粟床ãå©çšå¯èœãªã»ã³ãµãŒã®éãïŒäŸïŒã¢ãã€ã«ARäžã®WebXR vs. PC VRïŒã¯ããã©ãããã©ãŒã éã§äŸç¶ãšããŠç°ãªãäœéšã«ã€ãªããå¯èœæ§ããããŸãã
å°æ¥çã«ã¯ãé«åºŠãªè§ŠèŠãã£ãŒãããã¯ãèŠç·è¿œè·¡ãå šèº«è¿œè·¡ãªã©ãããã«æŽç·Žãããå ¥åæ¹æ³ãWebXRäœéšã«çµ±åãããããšãäºæ³ãããŸããWebXR Input Profile仿§ã¯ããããã®æ°ãããã©ãã€ã ã«å¯Ÿå¿ããããã«é²åãç¶ããã§ãããã
éçºè åãã®å®çšçãªæŽå¯
ã°ããŒãã«ãªèŠèŽè ã«å¯Ÿå¿ãã广çãªWebXRã¢ããªã±ãŒã·ã§ã³ãæ§ç¯ããããã«ã¯ïŒ
- ãããã¡ã€ã«ã®ç¢ºèªãåªå
ããïŒ å
¥åããã€ã¹ãèå¥ããããã®äž»èŠãªæ¹æ³ãšããŠãåžžã«
inputSource.profilesã䜿çšããŠãã ããã - ãã©ãŒã«ããã¯ãå®è£ ããïŒ ç¹å®ã®ãããã¡ã€ã«ãæ€åºãããªãå Žåã«ãGamepad APIãæ±çšã®ã€ã³ã¿ã©ã¯ã·ã§ã³ã¢ãã«ã䜿çšããŠãã¢ããªã±ãŒã·ã§ã³ãé©åã«æ©èœäœäžãŸãã¯é©å¿ããããã«èšèšããŠãã ããã
- åºç¯å²ã«ãã¹ãããïŒ å¯èœã§ããã°ãããŸããŸãªãã©ãããã©ãŒã ããã©ãŒã ãã¡ã¯ã¿ã«ããããã§ããã ãå€ãã®ç°ãªãXRããã€ã¹ã§ã¢ããªã±ãŒã·ã§ã³ããã¹ãããŠãã ããã
- æè»æ§ãèæ ®ããŠèšèšããïŒ ã¢ãžã¥ãŒã«åŒã§ãæ°ããããã€ã¹ããŠãŒã¶ãŒèšå®å¯èœãªã³ã³ãããŒã«ããµããŒãããããã«ç°¡åã«æ¡åŒµã§ããå ¥åãããã³ã°ã·ã¹ãã ãæ§ç¯ããŠãã ããã
- ãŠãŒã¶ãŒãã£ãŒãããã¯ãéµïŒ ã©ã®å ¥åãæ€åºããããããã©ã®ããã«ãããã³ã°ãããŠãããã«ã€ããŠããŠãŒã¶ãŒã«æç¢ºãªèŠèŠçåå³ãæäŸããŠãã ãããé©åãªå Žåã«ã¯ãŠãŒã¶ãŒã«ããã«ã¹ã¿ãã€ãºãèš±å¯ããŠãã ããã
- æåããã¢ã¯ã»ã·ããªãã£ãèæ ®ããïŒ ããŸããŸãªå ¥åæ¹æ³ããããŸããŸãªèœåãæã€ãŠãŒã¶ãŒã«ã©ã®ããã«åœ¹ç«ã€ããèããŠãã ããã
- ææ°æ å ±ãç¶æããïŒ WebXR APIããã³Input Profiles仿§ã®å€æŽã远å ã«ã€ããŠãåžžã«ææ°ã®æ å ±ãå ¥æããŠãã ããã
çµè«
WebXRã®å ¥åãœãŒã¹åé¡ãšã³ã³ãããŒã©ãŒã¿ã€ãæ€åºããã¹ã¿ãŒããããšã¯ãåãªãæè¡çãªè©³çްã§ã¯ãããŸãããããã¯ãäžçäžã®èŠèŽè ã«ãšã£ãŠå æ¬çã§ãçŽæçã§ã楜ããæ²¡å ¥åäœéšãåµé ããããã®åºæ¬ã§ããå ¥åãããã¡ã€ã«ã䞹念ã«åæããå ç¢ãªãã©ãŒã«ããã¯ã¡ã«ããºã ãå®è£ ããæè»æ§ã念é ã«çœ®ããŠèšèšããããšã§ãéçºè ã¯ããŠãŒã¶ãŒãã¡ã¿ããŒã¹ãæ¢æ±ããããã«éžæããããŒããŠã§ã¢ã«é¢ä¿ãªããWebXRã¢ããªã±ãŒã·ã§ã³ãã·ãŒã ã¬ã¹ã§é åçãªæ ãæäŸããããšãä¿èšŒã§ããŸãã